package org.oslims.client.presenter;

import java.util.List;
import java.util.Set;

import org.oslims.client.AsyncCall;
import org.oslims.client.GenericOSLimsException;
import org.oslims.client.MainEventBus;
import org.oslims.client.service.ParameterServiceAsync;
import org.oslims.client.uicomponents.SortableHeader;
import org.oslims.client.uicomponents.WidgetUtils;
import org.oslims.client.uicomponents.editbox.EditParameterBox;
import org.oslims.client.view.impl.ParameterEditorViewImpl;
import org.oslims.domain.Parameter;

import com.google.gwt.cell.client.ButtonCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.validation.client.InvalidConstraint;
import com.google.gwt.validation.client.interfaces.IValidator;
import com.google.gwt.view.client.ListView;
import com.google.gwt.view.client.Range;
import com.google.gwt.view.client.ListView.Delegate;
import com.mvp4g.client.annotation.InjectService;
import com.mvp4g.client.annotation.Presenter;
import com.mvp4g.client.presenter.BasePresenter;

@Presenter(view = ParameterEditorViewImpl.class)
public class ParameterPresenter extends BasePresenter<ParameterEditorViewImpl, MainEventBus> {

	private ParameterServiceAsync parameterService;
	private IValidator<Parameter> parameterValidator;

	private String currentSortProperty = "name";
	private Boolean currentSortDesc = false;

	public ParameterPresenter() {
		parameterValidator = GWT.create(Parameter.class);
	}

	public void onShowParameterManagement(DockLayoutPanel mainWidget) {

		WidgetUtils.removeCenterWidget(mainWidget);
		mainWidget.add(view.getViewWidget());
		refreshData();
	}

	public void bind() {

		bindEditBox();
		addColumns();
		setDelegate();

	}

	private void refreshData() {
		parameterService.getParameterCount(new AsyncCall<Integer>() {

			@Override
			protected void onFailureE(Throwable caught) {
				eventBus.error(caught.getMessage());
			}

			@Override
			protected void onSuccessE(Integer result) {
				view.getTable().setDataSize(result, true);

				if (result < view.getDefaultPageSize()) {
					view.getPager().setVisible(false);
					view.getTable().setPageSize(result);
				}
				view.getTable().refresh();
			}
		});
	}

	private void setDelegate() {
		view.getTable().setDelegate(new Delegate<Parameter>() {

			@Override
			public void onRangeChanged(ListView<Parameter> listView) {

				final Range r = listView.getRange();

				parameterService.getAllParameters(r.getStart(), r.getLength(), currentSortProperty, currentSortDesc, new AsyncCall<List<Parameter>>() {

					@Override
					protected void onFailureE(Throwable caught) {
						eventBus.error(caught.getMessage());
					}

					@Override
					protected void onSuccessE(List<Parameter> result) {
						view.getTable().setData(r.getStart(), r.getLength(), result);
						view.getTable().redraw();
					}
				});
			}
		});
	}

	private void addColumns() {
		final SortableHeader nameHeader = new SortableHeader("Name", "name");
		nameHeader.setSorted(true);
		nameHeader.setUpdater(new ValueUpdater<String>() {

			@Override
			public void update(String value) {
				nameHeader.toggleReverseSort();
				currentSortProperty = nameHeader.getPropertyName();
				currentSortDesc = nameHeader.getReverseSort();
				view.getTable().refresh();
				view.getTable().refreshHeaders();
			}
		});

		view.getTable().addColumn(new TextColumn<Parameter>() {

			@Override
			public String getValue(Parameter object) {
				return object.getName();
			}
		}, nameHeader);

		view.getTable().addColumn(new TextColumn<Parameter>() {

			@Override
			public String getValue(Parameter object) {
				return object.getUnit();
			}
		}, "Unit");

		view.getTable().addColumn(new TextColumn<Parameter>() {

			@Override
			public String getValue(Parameter object) {
				return object.getType();
			}
		}, "Type");

		Column<Parameter, String> editColumn = new Column<Parameter, String>(new ButtonCell()) {

			@Override
			public String getValue(Parameter object) {
				return "Edit";
			}
		};

		editColumn.setFieldUpdater(new FieldUpdater<Parameter, String>() {

			@Override
			public void update(int index, Parameter object, String value) {

				view.getEditParameterBox().showEdit(object);
			}
		});

		view.getTable().addColumn(editColumn);
	}

	private void bindEditBox() {
		view.getAddParameterButton().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent arg0) {
				view.getEditParameterBox().showNew();
			}
		});

		view.getEditParameterBox().getCancelButton().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent arg0) {
				view.getEditParameterBox().hide();
			}
		});

		view.getEditParameterBox().getSaveButton().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent arg0) {
				if (view.confirmEdit("Do you want to save your changes?"))
					saveParameter();
			}
		});
	}

	private void saveParameter() {

		EditParameterBox editBox = view.getEditParameterBox();
		Parameter tempParameter = editBox.getParameter();

		if (tempParameter == null)
			tempParameter = new Parameter();

		tempParameter.setName(editBox.getName().getValue());
		tempParameter.setUnit(editBox.getUnit().getValue());

		if (editBox.getType().getSelectedIndex() != -1) {
			tempParameter.setType(editBox.getType().getItemText(editBox.getType().getSelectedIndex()));
		}

		Set<InvalidConstraint<Parameter>> parameterErrors = parameterValidator.validate(tempParameter);

		if (parameterErrors.size() > 0) {
			for (InvalidConstraint<Parameter> ic : parameterErrors) {
				editBox.showError(ic.getItemName(), ic.getMessage());
			}
			return;
		}

		parameterService.saveOrUpdateParameter(tempParameter, new AsyncCall<Void>() {

			@Override
			public void onSuccessE(Void result) {

				view.getEditParameterBox().hide();
				refreshData();
			}

			@Override
			public void onFailureE(Throwable error) {

				if (error instanceof GenericOSLimsException) {
					view.getEditParameterBox().showError("name", "Name not unique");
				} else {
					eventBus.error(error.getMessage());
				}
			}
		});
	}

	@InjectService
	public void setParameterService(ParameterServiceAsync parameterService) {
		this.parameterService = parameterService;
	}
}
